// JavaScript Document
(function($){
	if (/*@cc_on!@*/false){
		$.event.special.input = {
			setup: function(d){
				if (d){
					$(this).bind('keyup.IE drop.IE cut.IE paste.IE', d, $.event.special.input._handler);
				} else {
					$(this).bind('keyup.IE drop.IE cut.IE paste.IE', $.event.special.input._handler);
				}
			},
			teardown: function(){
				$(this).unbind('keyup.IE drop.IE cut.IE paste.IE', $.event.special.input._handler);
			},
			_handler: function(e){
				var t = this,
					a = arguments;
				if (e.type !== 'keyup'){
					setTimeout(function(){
						$.event.special.input.handler.apply(t, a);
					},0);
				} else {
					$.event.special.input.handler.apply(t, a);
				}
			},
			handler: function(e){
				var el = e.target,
					name = el.tagName.toLocaleLowerCase();
				if (name !== 'input' && name !== 'textarea') return;
				if (name === 'input' && (el.type === 'button' || el.type === 'checkbox' || el.type === 'radio' || el.type === 'hidden' || el.type === 'image' || el.type === 'reset' || el.type === 'submit')) return;
				var symbolKey = (e.which >= 48 && e.which <= 90) || (e.which >= 96 && e.which <= 111) || (e.which >= 186 && e.which <= 222) || e.which === 32 || e.which === 13,
					deleteKey = e.which === 46 || e.which === 8;
				if (e.type === 'keyup' && (!symbolKey || (symbolKey && e.ctrlKey)) && !deleteKey) return;
				if (el._value !== el.value || e.type === 'drop' || e.type === 'paste' || e.type === 'cut'){
					e.type = 'input';
					$.event.handle.apply(this, arguments);
					el._value = el.value;
				}
			}
		};
	}
	
	$.event.special.changerMousewheel = {
		setup: function() {
			if (this.addEventListener)
				this.addEventListener('DOMMouseScroll', $.event.special.changerMousewheel.handler, false);
			this.onmousewheel = $.event.special.changerMousewheel.handler;
		},
		teardown: function() {
			if (this.removeEventListener)
				this.removeEventListener('DOMMouseScroll', $.event.special.changerMousewheel.handler, false);
			this.onmousewheel = null;
		},
		handler: function( event ) {
			event = $.event.fix(event || window.event);
			event.type = "changerMousewheel";
			event.delta = 0;
			event.delta = event.wheelDelta/-40 || event.detail;
			$.event.handle.apply( this, [event] );
			return ;
		}
	};
	
	
	$.fn.changerDisable = function(){
		this.filter(':input').each(function(){
			var self = $(this);
			if(!self.attr('disabled')) self.attr({disabled: 'disabled'})
				.trigger('disable');
		});
		return this;
	}
	
	$.fn.changerEnable = function(){
		this.filter(':input').each(function(){
			var self = $(this);
			if(self.attr('disabled')) self.removeAttr('disabled')
				.trigger('enable');
		});
		return this;
	}
	
	$.fn.changerSetChecked = function(){
		this.filter('input:checkbox, input:radio').each(function(){
			var self = $(this);
			if(!self.attr('checked')) self.attr({checked: 'checked'})
				.trigger('change');
		});
		return this;
	}
		
	$.fn.changerUnsetChecked = function(){
		this.filter('input:checkbox, input:radio').each(function(){
			var self = $(this);
			if(self.attr('checked')) self.removeAttr('checked')
				.trigger('change');
		});
		return this;
	}
	
	$.fn.changerSetReadonly = function(){
		this.filter('input:text, input:password, textarea').each(function(){
			var self = $(this);
			if(!self.attr('readonly')) self.attr({readonly: 'readonly'})
				.trigger('readonly');
		});
		return this;
	}
	
	$.fn.changerUnsetReadonly = function(){
		this.filter('input:text, input:password, textarea').each(function(){
			var self = $(this);
			if(self.attr('readonly')) self.removeAttr('readonly')
				.trigger('notReadonly');
		});
		return this;
	}
	
	function actions(self, wrap, e, cls, lCl){
		if(lCl) var label = self.data().changer.label;
		role = wrap.attr('role') || '';
		switch (e.type) {
			case 'mouseover': 
				wrap.addClass(cls.hover+role);
				if(label) label.addClass(lCl.hover);
				break;
			case 'mouseout': 
				wrap.removeClass(cls.hover+role);
				if(wrap.hasClass(cls.pressed+role)) self.trigger('unpress');
				if(label) label.removeClass(lCl.hover);
				break;
			case 'focus':
			case 'focusin': 
				wrap.addClass(cls.focused+role);
				if(label) label.addClass(lCl.focused);
				break;
			case 'blur':
			case 'focusout':
				wrap.removeClass(cls.focused);
				if(label) label.removeClass(lCl.focused);
				break;
			case 'disable': 
				wrap.addClass(cls.disabled);
				if(label) label.addClass(lCl.disabled);
				break;
			case 'enable': 
				wrap.removeClass(cls.disabled);
				if(label) label.removeClass(lCl.disabled);
				break;
			case 'mousedown': 
				self.trigger('press');
				break;
			case 'mouseup': 
				self.trigger('unpress');
				break;
			case 'press':
				wrap.addClass(cls.pressed+role);
				if(label) label.addClass(lCl.pressed);
				break;
			case 'unpress':
				wrap.removeClass(cls.pressed+role);
				if(label) label.removeClass(lCl.pressed);
				break;
			case 'readonly': 
				wrap.addClass(cls.readonly);
				break;
			case 'notReadonly': 
				wrap.removeClass(cls.readonly);
				break;
			case 'reset':
				self.trigger('change');
				break;
		}
	}
	
	$.fn.changerSelect = function(classes, options){
		var bodyEl = $('body'),
			cls = $.extend({
				base: 'changerSelect',
				wrap: 'Wrap',
				state: 'State',
				arrow: 'Arrow',
				list: 'List',
				listin:'Listin',
				optgroup: 'Optgroup',
				option: 'Option',
				selected: 'Selected',
				open: 'Open',
				hover: 'Hover',
				pressed: 'Pressed',
				focused: 'Focused',
				disabled: 'Disabled'
			}, classes || {}),
			opts = $.extend({
				wraps: 1,
				lists: 1,
				listsIn: true
			}, options || {});
			
		for(var cl in cls) {
			if(cl != 'base') cls[cl] = cls.base + cls[cl];
		}
		
		if(opts.wraps < 0) opts.wraps = 1;
			
		this.filter('select').each(function(){
			var sel = $(this);
			init(sel);
		});
		
		function init(sel){
			var hash = {};
			
			hash.sel = sel;	
			hash.data = sel.data().changer = {};
			hash.sel.multiple = sel.attr('multiple');
			hash.sel.sizeble = hash.sel.attr('size')<2?0:hash.sel.attr('size');
			
			//создаем обертки
			for(var i = 1; i <= opts.wraps; i++){
				if(i == 1) {
					//если первая обертка кладем её в хэш и дату(для работы извне)
					var wraps = [];
					sel.wrap($('<span/>', { 'class' : cls.wrap })); //создаем основную обертку
					hash.wrap = wraps[1] = hash.data.wrap = sel.parent(); //и оборачиваем ей селект
					if (sel[0].id){
						hash.wrap.addClass('id-' + sel[0].id);
					}
					continue;
				}
				wraps[i] = $('<span/>', { 'class' : cls.wrap+i });
				wraps[i-1].append(wraps[i]); //создаем остальные обертки
			}
			
			//создаем элементы выбраного значения и списка опшенов
			hash.state = $('<span/>', {'class': cls.state, role: 'State'});
			hash.arrow = $('<span/>', {'class': cls.arrow, role: 'Arrow'});
			
			//добавляем созданые элементы стрелки и состояния в обертку
			wraps[wraps.length-1]
				.append(hash.state)
				.append(hash.arrow);
			
			//создаем и добавляем обертки листа
			for(var i = 1; i <= opts.lists; i++){
				if(i == 1) {
					var lists = [];
					hash.list = lists[1] = $('<span/>', {'class': cls.list}); //создаем основную обертку листа
					hash.wrap.append(hash.list); //и добавляем ее в обертку всего селекта
					continue;
				}
				lists[i] = $('<span/>', { 'class' : cls.list+i });
				if(opts.listsIn) lists[i-1].append(lists[i]); //создаем остальные обертки листа
				else hash.list.append(lists[i]);
			}
			
			//переносим селект в конец обертки, чтобы не мозолил глаза в коде
			hash.list.after(sel);
			
			//создаем и добавялем внутренний лист
			hash.listin = $('<span/>', {'class': cls.listin, role: 'Listin'});
			if(opts.listsIn) lists[lists.length-1].append(hash.listin);
			else hash.list.append(hash.listin);
			
			//если есть атрибут сайз, инитим лист
			if(hash.sel.sizeble || hash.sel.multiple) {
				if(hash.sel.sizeble) hash.wrap.addClass('selectSizeble').addClass('selectSize' + hash.sel.attr('size'));
				else hash.wrap.addClass('selectMultiple');
				regenerateList(hash);
				hash.sel.sizeble?setSelected(hash):initSelectedMultyple(hash);
				checkToScroll(hash);
			}
									
			/**
				навешиваем обработчики событий
			*/
			hash.wrap.bind('change click mouseover mouseout focus focusin focusout disable enable mousedown mouseup press unpress reset', function(e){
				if(sel[0].disabled && e.type != 'disable' && e.type != 'change') return false;
				var self = $(e.target),
					selfRole = self.attr('role');
					isList = self.parents('.'+cls.list).length,
				 	wrap = !isList?hash.wrap:self;
					
				switch (e.type) {
					case 'click': 
						if(!isList){
							// IE - нажатие на внутренние элементы
							if($.browser.msie && self != wrap) wrap.focus();
							
							wrap.toggleClass(cls.open);
							openSelect(hash);
							bodyEl.mousedown(function(){
								bodyEl.bind('mouseup', closeSelect);
							});
						}
						else if(selfRole == 'Option'){
							if(!hash.sel.multiple){
								self.data().changerOption.attr({'selected':'selected'});
							
								if(hash.sel.sizeble) setSelected(hash);
								else {
									hash.wrap.removeClass(cls.open);
									hash.sel.trigger('change');
									hash.sel.trigger('focusout');
								}
									 
							}
							else{
								var opts = hash.sel[0].options;
								if(!e.ctrlKey){
									for(var i = 0, l = opts.length; i < l; i++){
										opts[i].selected = false;
									}
									self.data().changerOption.attr({'selected':'selected'});
									setSelected(hash);
								}
								else {
									if(self.data().changerOption[0].selected == true){
										self.data().changerOption[0].selected = false;
										setSelectedMultiple(hash, self, false);
									}
									else {
										self.data().changerOption[0].selected = true;
										setSelectedMultiple(hash, self, true);
									}
								}
							}
						}
						break;
					case 'change':
						hash.state.text($(sel[0].options[sel[0].selectedIndex]).text());
						break;
					case 'mouseover':
						if(!isList) actions(self, self, e, cls);
						actions(self, wrap, e, cls);
						break;
					case 'mouseout':
						if(!isList) actions(self, self, e, cls);
						actions(self, wrap, e, cls);
						break;
					case 'focus':
					case 'focusin':
						if(!self.hasClass(cls.wrap)) return false;
						actions(self, wrap, e, cls);
						break;
					case 'blur':
					case 'focusout':
						// для осла ретурним фолс, когда фокус перешел к чилде
						if(e.originalEvent && $(e.originalEvent.toElement).parents('.'+cls.wrap).length) return false;
						actions(self, wrap, e, cls);
					default:
						actions(self, wrap, e, cls);
						break;
				}
			});
			
			//скрываем реальный селект и сбрасываем табиндекс, чтобы не фокусился
			sel.attr({'tabindex':'-1'}).css({'position':'absolute', 'left':'-5000px'});
			
			//ставим обертке табиндекс, чтобы она начала получать фокус
			hash.wrap.attr({'tabindex':'0'});
			
			//вызываем функцию экшенов, чтобы инициировать начально состояние
			actions(sel, hash.wrap, {type: sel.context.disabled?'disable':'enable'}, cls);
			sel.trigger('change');
		};
				
		function openSelect(hash){
			regenerateList(hash);
			setSelected(hash);
			checkToScroll(hash);
		};
		
		function checkToScroll(hash){
			hash.listin[0].clientHeight;
			hash.listin.scrHgt = hash.listin[0].scrollHeight;
			
			// для осла 6 реализуем max-height выпадающего списка
			if($.browser.msie && $.browser.version < 7)
				hash.list.height(Math.min(parseInt(hash.list[0].currentStyle['max-height'] || 0), hash.listin.scrHgt) +"px");
								
			hash.list.hgt = hash.list.height();
			
			if(hash.list.hgt < hash.listin.scrHgt){
				if(!hash.scrollBar) createScroll(hash);
				else setScrollerHeight(hash);
			}
			
			scrollToSelected(hash);
		};
		
		function regenerateList(hash){
			hash.listin.empty();
			
			var opts = hash.sel[0].children;
			
			for(var i = 0, l = opts.length; i < l; i++){
				var opt = $(opts[i]),
					optElement = opt.data().changerElement;
				if(opt[0].nodeName.toLowerCase() == 'optgroup'){
					createOptgroup(opt, hash);
				}
				else if(optElement){
					optElement.data().changerOption = opt;
					hash.listin.append(optElement);
				}
				else createOption(opt, hash.listin, hash);
			}
			
			if(!hash.sel.multiple && opts.length && hash.sel[0].selectedIndex < 0) {
				opts[0].selected = true;
			}
		};
		
		function setSelected(hash){
			var opts = hash.sel[0].options,
				optElement = $(opts[hash.sel[0].selectedIndex]).data().changerElement;
			
			hash.listin.find('span').removeClass(cls.selected+'Option');
			optElement.addClass(cls.selected+'Option');
		};
		
		function setSelectedMultiple(hash, self, act){
			if(act) self.addClass(cls.selected+'Option');
			else self.removeClass(cls.selected+'Option');
		};
		
		function initSelectedMultyple(hash){
			var opts = hash.sel[0].options;
			
			for(var i = 0, l = opts.length; i < l; i++){
				var opt = $(opts[i]),
					optElement = opt.data().changerElement;
				if(opt[0].selected) optElement.addClass(cls.selected+'Option');
			}	
		}
		
		function scrollToSelected(hash){
			var opts = hash.sel[0].options;
			
			if(hash.scrollBar){ // если есть скролбар, скролим к селектнутому опшену 
				var optElement = $(opts[hash.sel[0].selectedIndex]).data().changerElement;
				
				hash.listin[0].scrollTop = optElement[0].offsetTop;
				scrollScroller(hash);
				
			}
		};
		
		function createOptgroup(group, hash){
			var optgroup = $('<span/>', {'class' : cls.optgroup, role: 'Optgroup'}),
				title = $('<span/>', {'class' : cls.base+'Title', 'role': 'Title'}).text(group.attr('label'));
			optgroup.append(title);	
			hash.listin.append(optgroup);
			// тоже самое делаем для вложеных для них опшенов
			for(var i = 0, l = group[0].children.length; i < l; i++){
				var opt = $(group[0].children[i]);
				createOption(opt, optgroup, hash);
			}
		};
		
		function createOption(opt, optgroup, hash){
			var option = $('<span/>', {'class': cls.option, role: 'Option'}).text(opt.text());
			option.data().changerOption = opt;
			opt.data().changerElement = option;
			optgroup.append(option);
		};
		
		function createScroll(hash){
			hash.scrollBar = $('<span/>', {'class':'scrollBar', role: 'scrollBar'});
			hash.scrollBarUp = $('<span/>', {'class':'scrollBarUpArrow', role: 'scrollBarUp'});
			hash.scrollBarDown = $('<span/>', {'class':'scrollBarDownArrow', role: 'scrollBarDown'});
			hash.scrollBarArea = $('<span/>', {'class':'scrollBarArea', role: 'scrollBarArea'});
			hash.scrollBarScroller = $('<span/>', {'class':'scrollBarScroller', role: 'scrollBarScroller'});
			
			hash.scrollBarScroller.append('<span class="scrollBarScrollerTop"/><span class="scrollBarScrollerImage"/><span class="scrollBarScrollerBottom"/>');
			
			hash.scrollBar.optHgt = hash.listin.find('.'+cls.option).eq(0).outerHeight();
			
			hash.list.append(hash.scrollBar);
			hash.scrollBar.append(hash.scrollBarUp).append(hash.scrollBarArea).append(hash.scrollBarDown);
			hash.scrollBarArea.append(hash.scrollBarScroller);
			
			hash.scrollBarUp.hgt = hash.scrollBarUp.height();
			hash.scrollBarDown.hgt = hash.scrollBarDown.height();
			hash.scrollBarArea.hgt = hash.scrollBar.height() - (hash.scrollBarUp.hgt + hash.scrollBarDown.hgt);
			
			//hash.listin.width(hash.listin.outerWidth()-hash.scrollBar.width());
			hash.listin.css('margin-right', hash.scrollBar.width());
			hash.scrollBarArea.height(hash.scrollBarArea.hgt);
			
			setScrollerHeight(hash);
			setScrollerEvents(hash);
		};
		
		function setScrollerHeight(hash){
			hash.listin.height(hash.list.hgt);
			
			hash.listin.height(); // дергаем высоту, чтобы ослы < 8 отрендерили элемент до того как будет считаться
			
			hash.scrollBarScroller.height(parseInt(hash.list.hgt/hash.listin.scrHgt*hash.scrollBarArea.hgt));
			
			// для осла 6 реализуем min-хейт скроллера
			if($.browser.msie && $.browser.version < 7) hash.scrollBarScroller.height(Math.max(parseInt(hash.scrollBarScroller[0].currentStyle['minHeight']), hash.scrollBarScroller.height())+'px');
			
			hash.scrollBarScroller.hgt = hash.scrollBarScroller.height();
		};
		
		function setScrollerEvents(hash){
			hash.list.bind('changerMousewheel', function(e){
				hash.listin.scrollTop(hash.listin[0].scrollTop+e.delta*hash.scrollBar.optHgt);
				scrollScroller(hash);
				return false;
			});
			hash.scrollBarUp.click(function(){
				scrollUp();
			}).mousedown(function(){
				
			}).mouseup(function(){
				
			});
			hash.scrollBarDown.click(function(){
				scrollDown();
			}).mousedown(function(){
				
			}).mouseup(function(){
				
			});
			hash.scrollBarScroller.mousedown(function(e){
				hash.scrollBarScroller.startCord = e.pageY;
				hash.scrollBarScroller.startScrollCord = parseInt(hash.scrollBarScroller.css('top'));
				bodyEl.bind('mousemove', dragDropScroller)
							.mouseup(function(){
								bodyEl.unbind('mousemove', dragDropScroller);
							});
				return false;
			});
			
			function scrollUp(){
				hash.listin.scrollTop(hash.listin[0].scrollTop-hash.scrollBar.optHgt);
				scrollScroller(hash);
			};
			
			function scrollDown(){
				hash.listin.scrollTop(hash.listin[0].scrollTop+hash.scrollBar.optHgt);
				scrollScroller(hash);
			};
			
			function dragDropScroller(e){
				var curCord = e.pageY,
					delta = hash.scrollBarScroller.startCord - curCord,
					scrollerTop = Math.min(Math.max(hash.scrollBarScroller.startScrollCord-delta, 0), hash.scrollBarArea.hgt - hash.scrollBarScroller.hgt);
				
				hash.scrollBarScroller.css({top: scrollerTop});
				
				hash.listin.scrollTop(scrollerTop*(hash.listin.scrHgt-hash.list.hgt)/(hash.scrollBarArea.hgt-hash.scrollBarScroller.hgt));
				return false;
			};	
		};
		
		function scrollScroller(hash){
			var scrollerTop = ((hash.scrollBarArea.hgt-hash.scrollBarScroller.hgt)*hash.listin[0].scrollTop)/(hash.listin.scrHgt-hash.list.hgt);
			hash.scrollBarScroller.css({top: scrollerTop});
		};
		
		function closeSelect(e){
			var t = $(e.target);
			$('.'+cls.open).not(t).not(t.parents('.'+cls.open)).removeClass(cls.open);
			$('.'+cls.focused).not(t).not(t.parents('.'+cls.focused)).removeClass(cls.focused);
			if(!$('.'+cls.open).length && !$('.'+cls.focused).length) bodyEl.unbind('mouseup', closeSelect);
		};
		
		return this;
	};
	
	$.fn.changerButton = function(classes, options){
		var cls = $.extend({
				base: 'changerBtn',
				wrap: 'Wrap',
				hover: 'Hover',
				pressed: 'Pressed',
				focused: 'Focused',
				disabled: 'Disabled',
				title: 'Title'
			}, classes || {}),
			opts = $.extend({
				wraps: 1,
				wrapsIn: true
			}, options || {});
		
		for(var cl in cls) {
			if(cl != 'base') cls[cl] = cls.base + cls[cl];
		}
		
		if(opts.wraps < 0) opts.wraps = 1;
		
		this.filter('input:submit, input:button, input:reset, button').each(function(){
			var btn = $(this);
			
			init(btn);
		});
		
		function init(btn){
			var hash = {};
			
			hash.btn = btn;
			hash.data = btn.data().changer = {};
						
			if(btn.attr('type') == 'reset') resetHandler(hash);
			
			//btn.wrap($('<span/>' ,{'class': cls.wrap}))
			
			//создаем обертки
			for(var i = 1; i <= opts.wraps; i++){
				if(i == 1) {
					//если первая обертка кладем её в хэш и дату(для работы извне)
					var wraps = [];
					btn.wrap($('<span/>', { 'class' : cls.wrap })); //создаем основную обертку
					hash.wrap = wraps[1] = hash.data.wrap = btn.parent(); //и оборачиваем ей селект
					if (btn[0].id){
						hash.wrap.addClass('id-' + btn[0].id);
					}
					continue;
				}
				wraps[i] = $('<span/>', { 'class' : cls.wrap+i });
				if(opts.wrapsIn){
					wraps[i-1].append(wraps[i]); //создаем остальные обертки
					wraps[i].append(btn);
				}
				else btn.before(wraps[i]);
			}	
				
			btn.before('<span class="'+cls.title+'">'+btn.val()+'</span>');
			
			btn.css({
				position: 'absolute',
				opacity: 0,
				filter: 'alpha(opacity=0)',
				top: 0,
				left: 0,
				padding: 0,
				margin: 0,
				border: 'none'
			});
			
			btn.height(hash.data.wrap[0].offsetHeight);
			btn.width(hash.data.wrap[0].offsetWidth);
			
			btn.bind('mouseover mouseout focus focusin blur focusout disable enable mousedown mouseup press unpress', function(e){
				var self = $(e.target),
					wrap = hash.wrap;
					actions(self, wrap, e, cls);
			});
			
			btn.triggerHandler(btn.context.disabled?'disable':'enable');
		};
		
		function resetHandler(hash){
			var form = $(hash.btn.context.form);
			if(!form.data().events || !form.data().events.reset)
				form.bind('reset', function(){
					var self = this;
					setTimeout(function(){
							for(var i = 0; i < self.elements.length; i++){
								var el = self.elements[i];
								/** для IE 6,7 - при отсуствии атрибута селектед хотя бы у одного опшена они возвращают в качестве вал херню */
								if($.browser.msie && el.nodeName.toLowerCase() == 'select' && (!$(el).val() || typeof($(el).val()) != 'string') && el.options.length) el.options[0].selected = true;
								/** end - for IE 6,7 */
								$(el).trigger('change');
							}
						}, 0);
				});
		};
		
		return this;
	};
				
	$.fn.changerText = function(classes, options){
		var self = $(this),
			cls = $.extend({
				base: 'changerText',
				wrap: 'Wrap',
				hover: 'Hover',
				pressed: 'Pressed',
				focused: 'Focused',
				filled: 'Filled',
				placeholder: 'Place',
				readonly: 'Readonly',
				disabled: 'Disabled'
			}, classes || {}),
			opts = $.extend({
				wraps: 1,
				wrapsIn: true
			}, options || {});
			
		for(var cl in cls) {
			if(cl != 'base') cls[cl] = cls.base + cls[cl];
		}
		
		if(opts.wraps < 0) opts.wraps = 1;
			
		this.filter('input:text, input:password').each(function(){
			var inpt = $(this);
			
			init(inpt);
		});
		
		function init(inpt){
			var hash = {};
			
			hash.inpt = inpt;
			hash.data = inpt.data().changer = {};
			
			//создаем обертки
			for(var i = 1; i <= opts.wraps; i++){
				if(i == 1) {
					//если первая обертка кладем её в хэш и дату(для работы извне)
					var wraps = [];
					inpt.wrap($('<span/>', { 'class' : cls.wrap })); //создаем основную обертку
					hash.wrap = wraps[1] = hash.data.wrap = inpt.parent(); //и оборачиваем ей селект
					if (inpt[0].id){
						hash.wrap.addClass('id-' + inpt[0].id);
					}
					continue;
				}
				wraps[i] = $('<span/>', { 'class' : cls.wrap+i });
				if(opts.wrapsIn){
					wraps[i-1].append(wraps[i]); //создаем остальные обертки
					wraps[i].append(inpt);
				}
				else inpt.before(wraps[i]);
			}
			
			if(inpt.attr('data-placeholder')) inpt.before($('<span class="' + cls.placeholder + '">' + inpt.attr('data-placeholder') + '</span>').click(function(){
				if(!inpt.context.disabled) inpt.trigger('focus');
			}));
			
			inpt.bind('change click mouseover mouseout focus focusin blur focusout disable enable readonly notReadonly mousedown mouseup press unpress reset', function(e){
				var self = $(e.target),
					wrap = hash.wrap;
				switch (e.type) {
					case 'change': 
						wrap[self.val()?'addClass':'removeClass'](cls.filled);
						break;
					default:
						actions(self, wrap, e, cls);
						break;
				}
			});
			
			inpt.triggerHandler('change');
			inpt.triggerHandler('focusout');
			inpt.triggerHandler(inpt[0].disabled?'disable':'enable');
			inpt.triggerHandler(inpt.attr('readonly')?'readonly':'notReadonly');
		};
		
		return this;
	};
	
	$.fn.changerFile = function(classes, options){
		var self = $(this),
			cls = $.extend({
				base: 'changerFile',
				wrap: 'Wrap',
				state: 'State',
				hover: 'Hover',
				pressed: 'Pressed',
				focused: 'Focused',
				filled: 'Filled',
				placeholder: 'Place',
				readonly: 'Readonly',
				disabled: 'Disabled'
			}, classes || {}),
			opts = $.extend({
				wraps: 1,
				wrapsIn: true
			}, options || {});
			
		for(var cl in cls) {
			if(cl != 'base') cls[cl] = cls.base + cls[cl];
		}
		
		if(opts.wraps <= 0) opts.wraps = 1;
			
		this.filter('input:file').each(function(){
			var inpt = $(this);
			
			init(inpt);
		});
		
		function init(inpt){
			var hash = {};
			
			hash.inpt = inpt;
			hash.data = inpt.data().changer = {};
			
			//создаем обертки
			for(var i = 1; i <= opts.wraps; i++){
				if(i == 1) {
					//если первая обертка кладем её в хэш и дату(для работы извне)
					var wraps = [];
					inpt.wrap($('<span/>', { 'class' : cls.wrap })); //создаем основную обертку
					hash.wrap = wraps[1] = hash.data.wrap = inpt.parent(); //и оборачиваем ей селект
					if (inpt[0].id){
						hash.wrap.addClass('id-' + inpt[0].id);
					}
					continue;
				}
				wraps[i] = $('<span/>', { 'class' : cls.wrap+i });
				if(opts.wrapsIn){
					wraps[i-1].append(wraps[i]); //создаем остальные обертки
					wraps[i].append(inpt);
				}
				else inpt.before(wraps[i]);
			}
			
			hash.state = $('<span/>', {'class':cls.state});
			hash.inpt.before(hash.state);
			
			inpt.bind('change click mouseover mouseout focus focusin blur focusout disable enable readonly notReadonly mousedown mouseup press unpress reset', function(e){
				var self = $(e.target),
					wrap = hash.wrap;
				switch (e.type) {
					case 'change': 
						wrap[self.val()?'addClass':'removeClass'](cls.filled);
						var val = hash.inpt.val();
						val = val.substring(val.lastIndexOf('\\')+1);
						hash.state.text(val);
						hash.inpt.attr('title',val);
						break;
					default:
						actions(self, wrap, e, cls);
						break;
				}
			});
			
			inpt.triggerHandler('change');
			inpt.triggerHandler('focusout');
			inpt.triggerHandler(inpt.context.disabled?'disable':'enable');
			inpt.triggerHandler(inpt.attr('readonly')?'readonly':'notReadonly');
			
			if(!inpt.val() && inpt.attr('data-placeholder')) hash.state.text(inpt.attr('data-placeholder'));
		};
		
		return this;
	};
	
	$.fn.changerCheck = function(classes, options){
		this.filter('input:radio, input:checkbox').each(function(){
			var check = $(this);
			
			init(check);
		});
		
		function init(check){
			var hash = {},
				type = check.attr('type').substring(0,1).toUpperCase()+check.attr('type').substring(1);
			
			var cls = $.extend({
					base: 'changer',
					wrap: 'Wrap',
					hover: 'Hover',
					pressed: 'Pressed',
					checked: 'Checked',
					focused: 'Focused',
					disabled: 'Disabled',
					state: 'State'
				}, classes || {}),
				lClasses = {}
				opts = $.extend({
					wraps: 1,
					wrapsIn: true
				}, options || {});
				
			cls.base += type;
				
			for(var cl in cls) {
				if(cl != 'base') cls[cl] = cls.base + cls[cl];
			}
			
			if(opts.wraps < 0) opts.wraps = 1;
			
			hash.check = check;
			hash.data = check.data().changer = {};
			
			//создаем обертки
			for(var i = 1; i <= opts.wraps; i++){
				if(i == 1) {
					//если первая обертка кладем её в хэш и дату(для работы извне)
					var wraps = [];
					check.wrap($('<span/>', { 'class' : cls.wrap })); //создаем основную обертку
					hash.wrap = wraps[1] = hash.data.wrap = check.parent(); //и оборачиваем ей селект
					if (check[0].id){
						hash.wrap.addClass('id-' + check[0].id);
					}
					continue;
				}
				wraps[i] = $('<span/>', { 'class' : cls.wrap+i });
				if(opts.wrapsIn){
					wraps[i-1].append(wraps[i]); //создаем остальные обертки
					wraps[i].append(check);
				}
				else check.before(wraps[i]);
			}
			
			check.css({
					opacity: 0,
					margin: 0,
					padding: 0,
					outline: 'none',
					'outline-width': 0,
					width: '100%',
					height: '100%',
					position: 'relative',
					'z-index': 10000
				})
				.before($('<span/>', {'class':cls.state}));
				
			check.bind('change click mouseover mouseout focus focusin blur focusout disable enable mousedown mouseup press unpress reset', function(e){
				var self = $(e.target),
					wrap = hash.wrap,
					checked = e.target.checked;
					
				switch (e.type) {
					case 'change':
					case 'click':
						wrap[checked?'addClass':'removeClass'](cls.checked);
						//self.data().changer.label[check?'addClass':'removeClass'](lClasses.checkedClass);
						if(checked && type == 'Radio'){
							var uncheckEls = $('input:radio[name='+self.attr('name')+']').not(self);
							uncheckEls.each(function(){
								var self = $(this);
								self.parent('span').removeClass(cls.checked);
								//if(self.data().changer && self.data().changer.label) 
								//	self.data().changer.label.removeClass(lClasses.checkedClass);
							});
						}
						break;
					default:
						actions(self, wrap, e, cls); //, lClasses
						break;
				}
			});
				
			check.triggerHandler('change');
			check.triggerHandler(check.context.disabled?'disable':'enable');
		}
		
		return this;
	};
	
	$.fn.changerTextarea = function(classes, options){
		var bodyEl = $('body'),
			cls = $.extend({
				base: 'changerTextarea',
				wrap: 'Wrap',
				hover: 'Hover',
				pressed: 'Pressed',
				focused: 'Focused',
				filled: 'Filled',
				placeholder: 'Place',
				readonly: 'Readonly',
				disabled: 'Disabled'
			}, classes || {}),
			opts = $.extend({
				wraps: 1,
				wrapsIn: true
			}, options || {});
			
		for(var cl in cls) {
			if(cl != 'base') cls[cl] = cls.base + cls[cl];
		}
		
		if(opts.wraps < 0) opts.wraps = 1;
			
		this.filter('textarea').each(function(){
			var inpt = $(this);
			
			init(inpt);
		});
		
		function init(inpt){
			var hash = {};
			
			hash.inpt = inpt;
			hash.data = inpt.data().changer = {};
			
			//создаем обертки
			for(var i = 1; i <= opts.wraps; i++){
				if(i == 1) {
					//если первая обертка кладем её в хэш и дату(для работы извне)
					var wraps = [];
					inpt.wrap($('<span/>', { 'class' : cls.wrap })); //создаем основную обертку
					hash.wrap = wraps[1] = hash.data.wrap = inpt.parent(); //и оборачиваем ей селект
					if (inpt[0].id){
						hash.wrap.addClass('id-' + inpt[0].id);
					}
					continue;
				}
				wraps[i] = $('<span/>', { 'class' : cls.wrap+i });
				if(opts.wrapsIn){
					wraps[i-1].append(wraps[i]); //создаем остальные обертки
					wraps[i].append(inpt);
				}
				else inpt.before(wraps[i]);
			}
			
			hash.list = wraps[wraps.length-1].addClass(cls.base+'InnerWrap');
			hash.listin = inpt;
			
			inpt.width(hash.list.width()+17);
				//.height(hash.list.height()+17);
			
			if(inpt.attr('data-placeholder')) inpt.before($('<span class="' + cls.placeholder + '">' + inpt.attr('data-placeholder') + '</span>').click(function(){
				if(!inpt.context.disabled) inpt.trigger('focus');
			}));
			
			inpt.bind('change click mouseover mouseout focus focusin blur focusout disable enable readonly notReadonly mousedown mouseup press unpress reset input keyup', function(e){
				var self = $(e.target),
					wrap = hash.wrap;
				switch (e.type) {
					case 'change': 
						wrap[self.val()?'addClass':'removeClass'](cls.filled);
						break;
					case 'input':
						checkToScroll(hash);
					case 'keyup':
						if(hash.scrollBar && hash.listin.scrTop != hash.listin[0].scrollTop){
							scrollScroller(hash);
						}
					default:
						actions(self, wrap, e, cls);
						break;
				}
			});
			
			inpt.triggerHandler('change');
			inpt.triggerHandler('focusout');
			inpt.triggerHandler(inpt[0].disabled?'disable':'enable');
			inpt.triggerHandler(inpt.attr('readonly')?'readonly':'notReadonly');
			
			checkToScroll(hash);
		};
		
		function checkToScroll(hash){
			hash.listin[0].clientHeight;
			hash.listin.scrHgt = hash.listin[0].scrollHeight;
			
			// для осла 6 реализуем max-height выпадающего списка
			//if($.browser.msie && $.browser.version < 7)
			//	hash.list.height(Math.min(parseInt(hash.list[0].currentStyle['max-height'] || 0), hash.listin.scrHgt) +"px");
								
			hash.list.hgt = hash.list.height();
			
			if(hash.list.hgt < hash.listin.scrHgt){
				if(!hash.scrollBar) {
					createScroll(hash);
					hash.wrap.addClass('withScroll');
					hash.inpt.width(hash.list.width()+17);
				}
				else setScrollerHeight(hash);
			}
			else{
				if(hash.scrollBar) hash.scrollBar.remove();
				hash.scrollBar = undefined;
				hash.wrap.removeClass('withScroll');
				hash.inpt.width(hash.list.width()+17);
			}
		};
		
						
		function createScroll(hash){
			hash.scrollBar = $('<span/>', {'class':'scrollBar', role: 'scrollBar'});
			hash.scrollBarUp = $('<span/>', {'class':'scrollBarUpArrow', role: 'scrollBarUp'});
			hash.scrollBarDown = $('<span/>', {'class':'scrollBarDownArrow', role: 'scrollBarDown'});
			hash.scrollBarArea = $('<span/>', {'class':'scrollBarArea', role: 'scrollBarArea'});
			hash.scrollBarScroller = $('<span/>', {'class':'scrollBarScroller', role: 'scrollBarScroller'});
			
			hash.scrollBarScroller.append('<span class="scrollBarScrollerTop"/><span class="scrollBarScrollerImage"/><span class="scrollBarScrollerBottom"/>');
			
			hash.scrollBar.optHgt = '15';
			
			hash.wrap.append(hash.scrollBar);
			hash.scrollBar.append(hash.scrollBarUp).append(hash.scrollBarArea).append(hash.scrollBarDown);
			hash.scrollBarArea.append(hash.scrollBarScroller);
			
			hash.scrollBarUp.hgt = hash.scrollBarUp.height();
			hash.scrollBarDown.hgt = hash.scrollBarDown.height();
			hash.scrollBarArea.hgt = hash.scrollBar.height() - (hash.scrollBarUp.hgt + hash.scrollBarDown.hgt);
			
			//hash.listin.width(hash.listin.outerWidth()-hash.scrollBar.width());
			//hash.listin.css('margin-right', hash.scrollBar.width());
			hash.scrollBarArea.height(hash.scrollBarArea.hgt);
			
			setScrollerHeight(hash);
			setScrollerEvents(hash);
		};
		
		function setScrollerHeight(hash){
			//hash.listin.height(hash.list.hgt);
			
			hash.listin.height(); // дергаем высоту, чтобы ослы < 8 отрендерили элемент до того как будет считаться
			
			hash.scrollBarScroller.stop().height(parseInt(hash.list.hgt/hash.listin.scrHgt*hash.scrollBarArea.hgt));
			
			// для осла 6 реализуем min-хейт скроллера
			if($.browser.msie && $.browser.version < 7) hash.scrollBarScroller.height(Math.max(parseInt(hash.scrollBarScroller[0].currentStyle['minHeight']), hash.scrollBarScroller.height())+'px');
			
			hash.scrollBarScroller.hgt = hash.scrollBarScroller.height();
		};
		
		function setScrollerEvents(hash){
			hash.list.bind('changerMousewheel', function(e){
				hash.listin.scrTop = hash.listin[0].scrollTop+e.delta*hash.scrollBar.optHgt;
				hash.listin.scrollTop(hash.listin.scrTop);
				scrollScroller(hash);
				return false;
			});
			hash.scrollBarUp.click(function(){
				scrollUp();
			}).mousedown(function(){
				
			}).mouseup(function(){
				
			});
			hash.scrollBarDown.click(function(){
				scrollDown();
			}).mousedown(function(){
				
			}).mouseup(function(){
				
			});
			hash.scrollBarScroller.mousedown(function(e){
				hash.scrollBarScroller.startCord = e.pageY;
				hash.scrollBarScroller.startScrollCord = parseInt(hash.scrollBarScroller.css('top'));
				bodyEl.bind('mousemove', dragDropScroller)
							.mouseup(function(){
								bodyEl.unbind('mousemove', dragDropScroller);
							});
				return false;
			});
			
			function scrollUp(){
				hash.listin.scrollTop(hash.listin[0].scrollTop-hash.scrollBar.optHgt);
				scrollScroller(hash);
			};
			
			function scrollDown(){
				hash.listin.scrollTop(hash.listin[0].scrollTop+hash.scrollBar.optHgt);
				scrollScroller(hash);
			};
			
			function dragDropScroller(e){
				var curCord = e.pageY,
					delta = hash.scrollBarScroller.startCord - curCord,
					scrollerTop = Math.min(Math.max(hash.scrollBarScroller.startScrollCord-delta, 0), hash.scrollBarArea.hgt - hash.scrollBarScroller.hgt);
				
				hash.scrollBarScroller.css({top: scrollerTop});
				
				hash.listin.scrTop = scrollerTop*(hash.listin.scrHgt-hash.list.hgt)/(hash.scrollBarArea.hgt-hash.scrollBarScroller.hgt);
				hash.listin.scrollTop(hash.listin.scrTop);
				return false;
			};	
		};
		
		function scrollScroller(hash){
			var scrollerTop = ((hash.scrollBarArea.hgt-hash.scrollBarScroller.hgt)*hash.listin[0].scrollTop)/(hash.listin.scrHgt-hash.list.hgt);
			hash.scrollBarScroller.css({top: scrollerTop});
		};
		
		return this;
	};
	
	$.fn.applyChanger = function(settings){
		var stgs = $.extend(true, {
				text: {options: {}, classes: {}},
				textarea: {options: {}, classes: {}},
				button: {options: {}, classes: {}},
				check: {options: {}, classes: {}},
				select: {options: {}, classes: {}},
				file: {options: {}, classes: {}}
			}, settings || {});
		
		if(stgs.all){	
			for(var stg in stgs){
				var cachStgs = {};
				$.extend(true, cachStgs, stgs[stg]);
				$.extend(true, stgs[stg], stgs.all);
				$.extend(true, stgs[stg], cachStgs);
			}
		}
		
		if(this.length > 0){
			var els;
			if(this.length == 1 && this[0].nodeName.toLowerCase() == 'form'){ 
				this.addClass('changerForm');
				els = $(":input", this);
			}
			else 
				els = this;
			
			apply(els, stgs);
		}
		
		function apply(elements, stgs) {
			elements = elements || 0;
			for(var i = 0, l = elements.length; i < l; i++){
				var element = $(elements[i]);
				switch(element[0].nodeName.toLowerCase()) {
					case 'input':
						switch(element.attr('type').toLowerCase()){
							case 'text':
							case 'password':
								element.changerText(stgs.text.classes, stgs.text.options);
								break;
							case 'submit':
							case 'reset':
							case 'button':
								element.changerButton(stgs.button.classes, stgs.button.options);
								break;
							case 'checkbox':
							case 'radio':
								element.changerCheck(stgs.check.classes, stgs.check.options);
								break;
							case 'file':
								element.changerFile(stgs.file.classes, stgs.file.options);
								break;
							case 'hidden':
								break;
							default:
								consoleLog('Form Changer: тип поля "'+element.attr('type')+'" не поддерживается');
						}
						break;
					case 'textarea':
						$(element).changerTextarea(stgs.textarea.classes, stgs.textarea.options);
						break;
					case 'select': 
						$(element).changerSelect(stgs.select.classes, stgs.select.options);
						break;
					default:
						consoleLog('Form Changer: в набор элементов попал элемент не относящийся к элементам форм - ', element);
				}
			}	
		}
		
		function consoleLog(str, element){
			if(console && console.log){
				console.log(str);
				if (element) console.log(element);
			}
		}
		
		return this;
	};
})(jQuery);